//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_PORTABILITY_PLATFORMS_MACOSX_ATOMIC_IPP
#define RS_PORTABILITY_PLATFORMS_MACOSX_ATOMIC_IPP

#ifndef RS_ATOMIC_IMPLEMENTATION_GUARD
#   error "Do not include this file directly! Instead include rs/Atomic.hpp"
#endif

#if RS_PLATFORM != RS_PLATFORM_MACOSX
#   error "Do not include this file on non-Mac OSX platforms!"
#endif

#include <libkern/OSAtomic.h>

namespace rs
{
    inline Int32 Atomic::AddFetch(Int32 volatile* address, Int32 value) {
        return OSAtomicAdd32(value, address);
    }
    
    inline UInt32 Atomic::AddFetch(UInt32 volatile* address, UInt32 value) {
        Int32 result = AddFetch(reinterpret_cast< Int32 volatile* >(address), reinterpret_cast< Int32& >(value));
        return reinterpret_cast< UInt32& >(result);
    }
    
    inline Int32 Atomic::AndFetch(Int32 volatile* address, Int32 value) {
        UInt32 result = AndFetch(reinterpret_cast< UInt32 volatile* >(address), reinterpret_cast< UInt32& >(value));
        return reinterpret_cast< Int32& >(result);    }
    
    inline UInt32 Atomic::AndFetch(UInt32 volatile* address, UInt32 value) {
        return OSAtomicAnd32(value, address);
    }
    
    inline Int32 Atomic::OrFetch(Int32 volatile* address, Int32 value) {
        UInt32 result = OrFetch(reinterpret_cast< UInt32 volatile* >(address), reinterpret_cast< UInt32& >(value));
        return reinterpret_cast< Int32& >(result);
    }
    
    inline UInt32 Atomic::OrFetch(UInt32 volatile* address, UInt32 value) {
        return OSAtomicOr32(value, address);
    }
    
    inline Int32 Atomic::XorFetch(Int32 volatile* address, Int32 value) {
        UInt32 result = XorFetch(reinterpret_cast< UInt32 volatile* >(address), reinterpret_cast< UInt32& >(value));
        return reinterpret_cast< Int32& >(result);
    }
    
    inline UInt32 Atomic::XorFetch(UInt32 volatile* address, UInt32 value) {
        return OSAtomicXor32(value, address);
    }
    
    inline Boolean Atomic::CompareSwap(Int32 volatile* address, Int32 oldValue, Int32 newValue) {
        return OSAtomicCompareAndSwap32(oldValue, newValue, address);
    }

    inline Boolean Atomic::CompareSwap(UInt32 volatile* address, UInt32 oldValue, UInt32 newValue) {
        return CompareSwap(reinterpret_cast< Int32 volatile* >(address), reinterpret_cast< Int32& >(oldValue), reinterpret_cast< Int32& >(newValue));
    }
    
    inline Boolean Atomic::CompareSwap(void* volatile* address, void* oldValue, void* newValue) {
        return OSAtomicCompareAndSwapPtr(oldValue, newValue, address);
    }
    
    inline Boolean Atomic::CompareSwap2(Int64 volatile* address, Int64 oldValue, Int64 newValue) {
        return OSAtomicCompareAndSwap64(oldValue, newValue, reinterpret_cast< int64_t volatile* >(address));
    }

    inline Boolean Atomic::CompareSwap2(UInt64 volatile* address, UInt64 oldValue, UInt64 newValue) {
        return CompareSwap2(reinterpret_cast< Int64 volatile* >(address), *reinterpret_cast< Int64* >(&oldValue), *reinterpret_cast< Int64* >(&newValue));
    }
    
    inline Boolean Atomic::CompareSwap2(void* volatile* address, void* oldValue, void* newValue) {
        return OSAtomicCompareAndSwapPtr(oldValue, newValue, address);
    }
}

#endif // RS_PORTABILITY_PLATFORMS_MACOSX_ATOMIC_IPP